library(DT)
Attaching package: ‘DT’
The following object is masked from ‘package:Seurat’:
JS
rr wolfrum <- readRDS(‘/projects/timshel/sc-scheele_lab_adipose_fluidigm_c1/data-wolfrum/wolfrum.compute.seurat_obj.rds’)
Which clusters are adipocytes/preadipocytes?

markers <- read.table('output/markergenes/wolfrum/markers_wolfrum.compute.seurat_obj.rds_seurat_clusters_negbinom', sep='\t', header=T)
Top 10 positive markers per cluster
Which clusters are the preadipocytes? Check by plotting some of the DE genes between T1T2T3 and T4T5 in the 180831 dataset.
top10_T1T2T3 <- T1T2T3[order(-T1T2T3$avg_logFC),][1:10]
Error in `[.data.frame`(T1T2T3[order(-T1T2T3$avg_logFC), ], 1:10) :
undefined columns selected
How do these genes look in the 180831 data?

How are they expressed in the Wolfrum data?

Not all genes are expressed clearly in specific clusters. It looks like cluster 22, 21, 5, 14, 23, 11 and 10 are the preadipocytes.

Also plot the top 10 ECM and Metabolic markers.
markers_u_l <- markers_u_l[order(-markers_u_l$avg_logFC)]
Error in `[.data.frame`(markers_u_l, order(-markers_u_l$avg_logFC)) :
undefined columns selected
How do these genes look in the 180831 data?

And how are they expressed in the Wolfrum data?
plots <- FeaturePlot(wolfrum, features=c(as.vector(markers_u$gene)[1:10], as.vector(markers_l$gene)[1:10]), pt.size=1, combine=F)
The following requested variables were not found: RP11-572C15.6
plot_grid(plotlist=plots, ncol=2)

The U and L branch markers are clearly expressed in the two clusters in the top right of the UMAP plot.
Check how many of the marker genes are found in each cluster.
kable(df[order(-df$total_overlap),]) %>%
kable_styling(bootstrap_options = "striped", full_width = F)
<table class="table table-striped" style="width: auto !important; margin-left: auto; margin-right: auto;">
<thead>
<tr>
<th style="text-align:left;"> </th>
<th style="text-align:right;"> total_overlap </th>
<th style="text-align:right;"> overlap_P </th>
<th style="text-align:right;"> overlap_L </th>
<th style="text-align:right;"> overlap_U </th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left;"> 11 </td>
<td style="text-align:right;"> 27 </td>
<td style="text-align:right;"> 13 </td>
<td style="text-align:right;"> 18 </td>
<td style="text-align:right;"> 0 </td>
</tr>
<tr>
<td style="text-align:left;"> 14 </td>
<td style="text-align:right;"> 23 </td>
<td style="text-align:right;"> 10 </td>
<td style="text-align:right;"> 2 </td>
<td style="text-align:right;"> 14 </td>
</tr>
<tr>
<td style="text-align:left;"> 22 </td>
<td style="text-align:right;"> 22 </td>
<td style="text-align:right;"> 15 </td>
<td style="text-align:right;"> 7 </td>
<td style="text-align:right;"> 5 </td>
</tr>
<tr>
<td style="text-align:left;"> 23 </td>
<td style="text-align:right;"> 20 </td>
<td style="text-align:right;"> 9 </td>
<td style="text-align:right;"> 2 </td>
<td style="text-align:right;"> 11 </td>
</tr>
<tr>
<td style="text-align:left;"> 10 </td>
<td style="text-align:right;"> 18 </td>
<td style="text-align:right;"> 12 </td>
<td style="text-align:right;"> 9 </td>
<td style="text-align:right;"> 0 </td>
</tr>
<tr>
<td style="text-align:left;"> 5 </td>
<td style="text-align:right;"> 10 </td>
<td style="text-align:right;"> 3 </td>
<td style="text-align:right;"> 0 </td>
<td style="text-align:right;"> 8 </td>
</tr>
<tr>
<td style="text-align:left;"> 24 </td>
<td style="text-align:right;"> 10 </td>
<td style="text-align:right;"> 8 </td>
<td style="text-align:right;"> 1 </td>
<td style="text-align:right;"> 2 </td>
</tr>
<tr>
<td style="text-align:left;"> 7 </td>
<td style="text-align:right;"> 6 </td>
<td style="text-align:right;"> 4 </td>
<td style="text-align:right;"> 1 </td>
<td style="text-align:right;"> 1 </td>
</tr>
<tr>
<td style="text-align:left;"> 13 </td>
<td style="text-align:right;"> 6 </td>
<td style="text-align:right;"> 2 </td>
<td style="text-align:right;"> 2 </td>
<td style="text-align:right;"> 2 </td>
</tr>
<tr>
<td style="text-align:left;"> 2 </td>
<td style="text-align:right;"> 5 </td>
<td style="text-align:right;"> 4 </td>
<td style="text-align:right;"> 1 </td>
<td style="text-align:right;"> 0 </td>
</tr>
<tr>
<td style="text-align:left;"> 3 </td>
<td style="text-align:right;"> 4 </td>
<td style="text-align:right;"> 3 </td>
<td style="text-align:right;"> 1 </td>
<td style="text-align:right;"> 0 </td>
</tr>
<tr>
<td style="text-align:left;"> 15 </td>
<td style="text-align:right;"> 4 </td>
<td style="text-align:right;"> 2 </td>
<td style="text-align:right;"> 2 </td>
<td style="text-align:right;"> 0 </td>
</tr>
<tr>
<td style="text-align:left;"> 19 </td>
<td style="text-align:right;"> 4 </td>
<td style="text-align:right;"> 3 </td>
<td style="text-align:right;"> 1 </td>
<td style="text-align:right;"> 1 </td>
</tr>
<tr>
<td style="text-align:left;"> 18 </td>
<td style="text-align:right;"> 3 </td>
<td style="text-align:right;"> 1 </td>
<td style="text-align:right;"> 2 </td>
<td style="text-align:right;"> 0 </td>
</tr>
<tr>
<td style="text-align:left;"> 4 </td>
<td style="text-align:right;"> 2 </td>
<td style="text-align:right;"> 1 </td>
<td style="text-align:right;"> 1 </td>
<td style="text-align:right;"> 0 </td>
</tr>
<tr>
<td style="text-align:left;"> 6 </td>
<td style="text-align:right;"> 2 </td>
<td style="text-align:right;"> 2 </td>
<td style="text-align:right;"> 0 </td>
<td style="text-align:right;"> 0 </td>
</tr>
<tr>
<td style="text-align:left;"> 8 </td>
<td style="text-align:right;"> 2 </td>
<td style="text-align:right;"> 0 </td>
<td style="text-align:right;"> 2 </td>
<td style="text-align:right;"> 0 </td>
</tr>
<tr>
<td style="text-align:left;"> 12 </td>
<td style="text-align:right;"> 2 </td>
<td style="text-align:right;"> 1 </td>
<td style="text-align:right;"> 0 </td>
<td style="text-align:right;"> 1 </td>
</tr>
<tr>
<td style="text-align:left;"> 20 </td>
<td style="text-align:right;"> 2 </td>
<td style="text-align:right;"> 2 </td>
<td style="text-align:right;"> 1 </td>
<td style="text-align:right;"> 0 </td>
</tr>
<tr>
<td style="text-align:left;"> 21 </td>
<td style="text-align:right;"> 2 </td>
<td style="text-align:right;"> 0 </td>
<td style="text-align:right;"> 1 </td>
<td style="text-align:right;"> 1 </td>
</tr>
<tr>
<td style="text-align:left;"> 1 </td>
<td style="text-align:right;"> 0 </td>
<td style="text-align:right;"> 0 </td>
<td style="text-align:right;"> 0 </td>
<td style="text-align:right;"> 0 </td>
</tr>
<tr>
<td style="text-align:left;"> 9 </td>
<td style="text-align:right;"> 0 </td>
<td style="text-align:right;"> 0 </td>
<td style="text-align:right;"> 0 </td>
<td style="text-align:right;"> 0 </td>
</tr>
<tr>
<td style="text-align:left;"> 16 </td>
<td style="text-align:right;"> 0 </td>
<td style="text-align:right;"> 0 </td>
<td style="text-align:right;"> 0 </td>
<td style="text-align:right;"> 0 </td>
</tr>
<tr>
<td style="text-align:left;"> 17 </td>
<td style="text-align:right;"> 0 </td>
<td style="text-align:right;"> 0 </td>
<td style="text-align:right;"> 0 </td>
<td style="text-align:right;"> 0 </td>
</tr>
<tr>
<td style="text-align:left;"> 25 </td>
<td style="text-align:right;"> 0 </td>
<td style="text-align:right;"> 0 </td>
<td style="text-align:right;"> 0 </td>
<td style="text-align:right;"> 0 </td>
</tr>
<tr>
<td style="text-align:left;"> 26 </td>
<td style="text-align:right;"> 0 </td>
<td style="text-align:right;"> 0 </td>
<td style="text-align:right;"> 0 </td>
<td style="text-align:right;"> 0 </td>
</tr>
</tbody>
</table>
Table shows the percentage of genes with avgLogFC > 0.7 that was found in the cluster. Sort on columns to get the top clusters.
logfc_0.5_genes_100 <- get_gene_overlap_per_cluster(0.5, 100)
datatable(logfc_0.5_genes_100)
Check the top 5 clusters per branch for different n_genes and min logFC
logfc <- c(0.25, 0.5, 0.7)
n_genes <- c(100, 100, 100)
for (i in 1:length(logfc)){
print(paste('min_logFC: ', logfc[i], ' | n_genes: ', n_genes[i], sep=''))
df <- get_gene_overlap_per_cluster(logfc[i], n_genes[i])
print_top_clusters(df)
}
[1] "min_logFC: 0.25 | n_genes: 100"
[1] "P: 24, 11, 22"
[1] "L: 11, 10, 23"
[1] "U: 14, 24, 23"
[1] "min_logFC: 0.5 | n_genes: 100"
[1] "P: 24, 11, 22"
[1] "L: 11, 10, 23"
[1] "U: 14, 23, 24"
[1] "min_logFC: 0.7 | n_genes: 100"
[1] "P: 24, 11, 19"
[1] "L: 11, 10, 23"
[1] "U: 14, 23, 22"
There is some overlap between branches which is good. Cluster 11 is shared between P and L, cluster 14 is shared between P and U and cluster 23 is shared between L and U. This would indicate that cluster 24 contains most immature preadipocytes, cluster 10 contains most mature L branch cells and cluster 22 contains most mature U branch cells.\
Based on the results:\ P = 24\ L = 11\ U = 14\
Hypothesis: cluster 23 represents preadipocytes at the start of differentation (the cell states between T3 and T4 in 180831 data that we missed). Cluster 5 represents even more mature metabolic cells and cluster 11 represents more mature ECM cells.\
Clusters 22 shares most genes with the P branch. Cluster 23 most with the U branch. (see datatable above). These could also represent the preadipocytes at start of differentiation or the cells that transfer back to progenitor cells. \


Seurat integration of Wolfrum and 10x-180831 data

These results also confirm that the L branch is closest to cluster 11 and U is closest to the U branch.\
Seurat integration of Wolfrum preadiopcyte subset and 10x-180831 data
integrated.subset@meta.data[which(is.na(integrated.subset@meta.data$branch)), 'dataset'] <- 'Wolfrum'
Error in integrated.subset@meta.data[which(is.na(integrated.subset@meta.data$branch)), :
object 'integrated.subset' not found
Predict cell types with Seurat’s TransferData
wolfrum.predicted_labels <- readRDS('output/seurat_objects/wolfrum/wolfrum.predicted_labels_180831.rds')
Used pca, pca.project and cca as dimred for FindTransferAnchors and IntegrateData. \
Scores for P cells

Scores for U cells

Scores for L cells

For all predictions, change predicted id to NA if max score is below a certain threshold.
assign_labels <- function(colname, threshold=0.5){
pred_ids <- unlist(as.vector(apply(wolfrum.predicted_labels@meta.data[,c(paste(colname,'.prediction.score.max', sep=''), paste(colname, '.predicted.id', sep=''))], 1, function(x){
if (x[[1]] < threshold){
return(NA)
} else{
return(x[[2]])
}
})))
return(pred_ids)
}
for (col in c('predictions_pca_project', 'predictions_pca', 'predictions_cca.')){
for (t in c(0.5, 0.7, 0.9, 0.95, 0.99)){
preds <- assign_labels(col, t)
wolfrum.predicted_labels <- AddMetaData(wolfrum.predicted_labels, preds, col.name=paste(col, 'predicted_label', t, sep='.'))
}
}
Threshold for prediction = 0.5
plot_grid(
UMAPPlot(wolfrum.predicted_labels, group.by='predictions_pca.predicted_label.0.5'),
UMAPPlot(wolfrum.predicted_labels, group.by='predictions_pca_project.predicted_label.0.5'),
UMAPPlot(wolfrum.predicted_labels, group.by='predictions_cca..predicted_label.0.5'), ncol=2
)
Threshold for prediction = 0.7

Threshold for prediction = 0.9

Only show preadipocytes
Figures
labels <- unlist(lapply(wolfrum.predicted_labels@meta.data$predictions_pca.predicted_label.0.7, function(x){
if (is.na(x)){
return('Non-maching cells')
} if(x == 'ECM'){
Error: unexpected 'if' in:
" return('Non-maching cells')
} if"

save_plot("figures/figures_paper/main_figures/Figure_wolfrum/UMAP_wolfrum_predicted-labels_180831.pdf", p_predictions, base_width=8, base_height=5)
Error in grDevices::pdf(file = filename, ..., version = version) :
cannot open file 'figures/figures_paper/main_figures/Figure_wolfrum/UMAP_wolfrum_predicted-labels_180831.pdf'
p <- UMAPPlot(wolfrum.predicted_labels, group.by='RNA_snn_res.0.8', label=T, no.axes=T, no.legend=T) + theme(legend.position = "none", axis.text = element_blank(), axis.ticks = element_blank(), axis.title = element_blank(), plot.margin=grid::unit(c(0,0,0,0), "mm"))
The following functions and any applicable methods accept the dots: CombinePlots
#save_plot("figures/figures_paper/main_figures/Figure_wolfrum/UMAP_wolfrum_clusters.pdf", p_clusters, base_width=6, base_height=5)
#featureplots
#widht=13
#ucp2_fp <- featureplots_leg$UCP2 + scale_color_gradient(name='Expression', low='gray', #high='blue', guide='colorbar', limits=c(0,5)) + theme(plot.title=element_blank(), #legend.title=element_text(size=20), legend.text=element_text(size=20), legend.key.height = #unit(1.3, 'cm'))
#dcn_fp <- featureplots_noleg$DCN + theme(plot.title=element_blank())
adipoq <- FeaturePlot(wolfrum.predicted_labels, features='ADIPOQ') + NoLegend() + NoAxes() + theme(plot.title = element_text(size=20)) + scale_color_gradient(name='Expression', low='gray', high='blue', guide='colorbar', limits=c(0,5))
lipe <- FeaturePlot(wolfrum.predicted_labels, features='LIPE') + NoLegend() + NoAxes() + theme(plot.title = element_text(size=20)) + scale_color_gradient(name='Expression', low='gray', high='blue', guide='colorbar', limits=c(0,5))
apod <- FeaturePlot(wolfrum.predicted_labels, features='APOD') + NoLegend() + NoAxes() + theme(plot.title = element_text(size=20)) + scale_color_gradient(name='Expression', low='gray', high='blue', guide='colorbar', limits=c(0,5))
dcn <- FeaturePlot(wolfrum.predicted_labels, features='DCN') + NoAxes() + theme(plot.title = element_text(size=20), legend.text=element_text(size=20), legend.key.height = unit(1.3, 'cm')) + scale_color_gradient(name='Expression', low='gray', high='blue', guide='colorbar', limits=c(0,5))

#save_plot("../figures/figures_paper/main_figures/Figure_wolfrum/featureplots.pdf", g, base_width=16, base_height=4)
EBF2 and LEP
pparg <- FeaturePlot(wolfrum.predicted_labels, features='PPARG') + NoAxes() + theme(plot.title = element_text(size=20), legend.text=element_text(size=20), legend.key.height = unit(1.3, 'cm')) + scale_color_gradient(name='Expression', low='gray', high='blue', guide='colorbar')
Scale for 'colour' is already present. Adding another scale for
'colour', which will replace the existing scale.



save_plot("figures/figures_paper/main_figures/Figure_wolfrum/UMAP_adipocyte_clusters.pdf", p, base_width=6, base_height=5)
Error in grDevices::pdf(file = filename, ..., version = version) :
cannot open file 'figures/figures_paper/main_figures/Figure_wolfrum/UMAP_adipocyte_clusters.pdf'
ebf2 <- FeaturePlot(wolfrum.predicted_labels, features='EBF2', pt.size=0.5) + NoLegend() + NoAxes() + theme(plot.title = element_text(size=20)) + scale_color_gradient(name='Expression', low='gray', high='blue', guide='colorbar', limits=c(0,5))
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the
existing scale.
pparg <- FeaturePlot(wolfrum.predicted_labels, features='PPARG', pt.size=0.5) + NoAxes() + theme(plot.title = element_text(size=20), legend.text=element_text(size=15), legend.key.height = unit(1.3, 'cm')) + scale_color_gradient(name='Expression', low='gray', high='blue', guide='colorbar', limits=c(0,5))
Scale for 'colour' is already present. Adding another scale for 'colour', which will replace the
existing scale.
g <- plot_grid(
ebf2, pparg, ncol=2, rel_widths = c(1, 1.3)
)
g

plots <- VlnPlot(wolfrum.predicted_labels, features=c('ADIPOQ', 'LIPE', 'PLIN4', 'FABP4', 'ADIRF', 'APOD', 'MGP', 'DCN', 'CCDC80', 'PLAC9'), group.by='RNA_snn_res.0.8', pt.size=-1, combine=F)
for (i in 1:length(plots)){
if (i == length(plots)){
plots[[i]] <- plots[[i]] + NoLegend() +
theme(plot.title=element_blank(),
axis.title.y=element_blank(),
axis.line.x=element_blank(),
axis.text.x=element_text(angle=0, size=12),
plot.margin = unit(c(0, 0, 0, 0), "cm")) +
labs(x='Cluster')
} else {
plots[[i]] <- plots[[i]] + NoLegend() +
theme(plot.title=element_blank(),
axis.title.y=element_blank(),
axis.line.x=element_blank(),
axis.ticks.x=element_blank(),
axis.text.x=element_blank(),
axis.title.x=element_blank(),
plot.margin = unit(c(0, 0, 0, 0), "cm"))
}
}
vlnplts <- plot_grid(plotlist=plots, ncol=1, rel_heights=c(1,1,1,1,1,1,1,1,1,1.6))
vlnplts
#save_plot("figures/figures_paper/main_figures/Figure_wolfrum/violinplots.pdf", p, base_width=6, base_height=8)
Supplementary figure
integrated <- readRDS('output/seurat_objects/wolfrum/wolfrum.180831.integrated.rds')
sfig <- plot_grid(
UMAPPlot(integrated, group.by='dataset'),
UMAPPlot(integrated, group.by='State.labels', cols=colormap.branches),
UMAPPlot(integrated, group.by='RNA_snn_res.0.8', label=T) + NoLegend(), ncol=2
)
sfig
#save_plot("figures/figures_paper/supplementary_figures/wolfrum/integration.wolfrum.180831.pdf", sfig, base_width=12, base_height=8)
LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKCmBgYHtyIG1lc3NhZ2U9Rn0KbGlicmFyeShTZXVyYXQpCmxpYnJhcnkobW9ub2NsZSkKbGlicmFyeShjb3dwbG90KQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHRpZHlyKQpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KGthYmxlRXh0cmEpCmxpYnJhcnkoRFQpCmBgYAoKYGBge3J9CndvbGZydW0gPC0gcmVhZFJEUygnL3Byb2plY3RzL3RpbXNoZWwvc2Mtc2NoZWVsZV9sYWJfYWRpcG9zZV9mbHVpZGlnbV9jMS9kYXRhLXdvbGZydW0vd29sZnJ1bS5jb21wdXRlLnNldXJhdF9vYmoucmRzJykKZGF0YV8xODA4MzEgPC0gcmVhZFJEUygnL3Byb2plY3RzL3B5dHJpay9zY19hZGlwb3NlL2FuYWx5emVfMTB4X2ZsdWlkaWdtLzEweC1hZGlwb2N5dGUtYW5hbHlzaXMvb3V0cHV0L3NldXJhdF9vYmplY3RzLzE4MDgzMS8xMHgtMTgwODMxLVMzJykKYGBgCgoKCiNXaGljaCBjbHVzdGVycyBhcmUgYWRpcG9jeXRlcy9wcmVhZGlwb2N5dGVzPwoKYGBge3IgZmlnLmhlaWdodCA9IDQsIGZpZy53aWR0aCA9IDEyLCBmaWcuYWxpZ24gPSAiY2VudGVyIn0KcGxvdF9ncmlkKAogIFVNQVBQbG90KHdvbGZydW0sIGdyb3VwLmJ5PSdvcmlnLmlkZW50JywgbGFiZWw9VCksCiAgVU1BUFBsb3Qod29sZnJ1bSwgZ3JvdXAuYnk9J3NldXJhdF9jbHVzdGVycycsIGxhYmVsPVQpCikKYGBgCgpgYGB7cn0KbWFya2VycyA8LSByZWFkLnRhYmxlKCdvdXRwdXQvbWFya2VyZ2VuZXMvd29sZnJ1bS9tYXJrZXJzX3dvbGZydW0uY29tcHV0ZS5zZXVyYXRfb2JqLnJkc19zZXVyYXRfY2x1c3RlcnNfbmVnYmlub20nLCBzZXA9J1x0JywgaGVhZGVyPVQpCmBgYAoKVG9wIDEwIHBvc2l0aXZlIG1hcmtlcnMgcGVyIGNsdXN0ZXIgCgpgYGB7cn0KcG9zX21hcmtlcnNfdG9wMTAgPC0gbWFya2VycyAlPiUgCiAgZ3JvdXBfYnkoY2x1c3RlcikgJT4lIAogIHRvcF9uKG49MTAsIHd0PWF2Z19sb2dGQykKICAKbmVnX21hcmtlcnNfdG9wMjAgPC0gbWFya2VycyAlPiUgCiAgZ3JvdXBfYnkoY2x1c3RlcikgJT4lIAogIHRvcF9uKG49Niwgd3Q9ZGVzYyhhdmdfbG9nRkMpKQoKcG9zX21hcmtlcnNfdG9wMTAKYGBgCgpXaGljaCBjbHVzdGVycyBhcmUgdGhlIHByZWFkaXBvY3l0ZXM/IENoZWNrIGJ5IHBsb3R0aW5nIHNvbWUgb2YgdGhlIERFIGdlbmVzIGJldHdlZW4gVDFUMlQzIGFuZCBUNFQ1IGluIHRoZSAxODA4MzEgZGF0YXNldC4KCmBgYHtyfQojREUgZ2VuZXMgYmV0d2VlbiBUMVQyVDMgYW5kIFQ0VDUgaW4gdGhlIDEweC0xODA4MzEgZGF0YS4KbWFya2Vyc19UMVQyVDNfVDRUNSA8LSByZWFkLnRhYmxlKCdvdXRwdXQvbWFya2VyZ2VuZXMvMTgwODMxL21hcmtlcnNfMTB4LTE4MDgzMV90aW1lX2NvbWJpbmVkX25lZ2Jpbm9tJywgaGVhZGVyPVQpCm1hcmtlcnNfVDFUMlQzX1Q0VDUgPC0gbWFya2Vyc19UMVQyVDNfVDRUNVtvcmRlcigtbWFya2Vyc19UMVQyVDNfVDRUNSRhdmdfbG9nRkMpLF0KbWFya2Vyc19UMVQyVDMgPC0gbWFya2Vyc19UMVQyVDNfVDRUNVt3aGljaChtYXJrZXJzX1QxVDJUM19UNFQ1JGNsdXN0ZXIgPT0gMSksXQptYXJrZXJzX1Q0VDUgPC0gbWFya2Vyc19UMVQyVDNfVDRUNVt3aGljaChtYXJrZXJzX1QxVDJUM19UNFQ1JGNsdXN0ZXIgPT0gMiksXQpgYGAKCkhvdyBkbyB0aGVzZSBnZW5lcyBsb29rIGluIHRoZSAxODA4MzEgZGF0YT8KCmBgYHtyLCBmaWcuaGVpZ2h0ID0gMTIsIGZpZy53aWR0aCA9IDEyLCBmaWcuYWxpZ24gPSAiY2VudGVyIn0KcGxvdHMgPC0gRmVhdHVyZVBsb3QoZGF0YV8xODA4MzEsIGZlYXR1cmVzPWMoYXMudmVjdG9yKG1hcmtlcnNfVDFUMlQzJGdlbmUpWzE6MTBdLCBhcy52ZWN0b3IobWFya2Vyc19UNFQ1JGdlbmUpWzE6MTBdKSwgcHQuc2l6ZT0xLCBjb21iaW5lPUYpCnBsb3RfZ3JpZChwbG90bGlzdD1wbG90cywgbmNvbD00KQpgYGAKCkhvdyBhcmUgdGhleSBleHByZXNzZWQgaW4gdGhlIFdvbGZydW0gZGF0YT8KCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNTAsIGZpZy53aWR0aCA9IDEyLCBmaWcuYWxpZ24gPSAiY2VudGVyIn0KcGxvdHMgPC0gRmVhdHVyZVBsb3Qod29sZnJ1bSwgZmVhdHVyZXM9Yyhhcy52ZWN0b3IobWFya2Vyc19UMVQyVDMkZ2VuZSlbMToxMF0sIGFzLnZlY3RvcihtYXJrZXJzX1Q0VDUkZ2VuZSlbMToxMF0pLCBwdC5zaXplPTEsIGNvbWJpbmU9RikKcGxvdF9ncmlkKHBsb3RsaXN0PXBsb3RzLCBuY29sPTIpCmBgYAoKTm90IGFsbCBnZW5lcyBhcmUgZXhwcmVzc2VkIGNsZWFybHkgaW4gc3BlY2lmaWMgY2x1c3RlcnMuIEl0IGxvb2tzIGxpa2UgY2x1c3RlciAyMiwgMjEsIDUsIDE0LCAyMywgMTEgYW5kIDEwIGFyZSB0aGUgcHJlYWRpcG9jeXRlcy4gCgpgYGB7cn0KVU1BUFBsb3Qod29sZnJ1bSwgZ3JvdXAuYnk9J3NldXJhdF9jbHVzdGVycycsIGxhYmVsPVQpCmBgYAoKQWxzbyBwbG90IHRoZSB0b3AgMTAgRUNNIGFuZCBNZXRhYm9saWMgbWFya2Vycy4KCmBgYHtyfQojREUgZ2VuZXMgYmV0d2VlbiBUMVQyVDMgYW5kIFQ0VDUgaW4gdGhlIDEweC0xODA4MzEgZGF0YS4KbWFya2Vyc191X2wgPC0gcmVhZC50YWJsZSgnb3V0cHV0L21hcmtlcmdlbmVzLzE4MDgzMS9tYXJrZXJzXzEweC0xODA4MzFfdXBwZXJicmFuY2hfbG93ZXJicmFuY2hfbmVnYmlub20nLCBzZXA9J1x0JywgaGVhZGVyPVQpCm1hcmtlcnNfdSA8LSBtYXJrZXJzX3VfbFtvcmRlcigtbWFya2Vyc191X2wkYXZnX2xvZ0ZDKSxdCm1hcmtlcnNfbCA8LSBtYXJrZXJzX3VfbFtvcmRlcihtYXJrZXJzX3VfbCRhdmdfbG9nRkMpLF0KYGBgCgpIb3cgZG8gdGhlc2UgZ2VuZXMgbG9vayBpbiB0aGUgMTgwODMxIGRhdGE/CgpgYGB7ciwgZmlnLmhlaWdodCA9IDEyLCBmaWcud2lkdGggPSAxMiwgZmlnLmFsaWduID0gImNlbnRlciJ9CnBsb3RzIDwtIEZlYXR1cmVQbG90KGRhdGFfMTgwODMxLCBmZWF0dXJlcz1jKGFzLnZlY3RvcihtYXJrZXJzX3UkZ2VuZSlbMToxMF0sIGFzLnZlY3RvcihtYXJrZXJzX2wkZ2VuZSlbMToxMF0pLCBwdC5zaXplPTEsIGNvbWJpbmU9RikKcGxvdF9ncmlkKHBsb3RsaXN0PXBsb3RzLCBuY29sPTQpCmBgYAoKQW5kIGhvdyBhcmUgdGhleSBleHByZXNzZWQgaW4gdGhlIFdvbGZydW0gZGF0YT8KCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNTAsIGZpZy53aWR0aCA9IDEyLCBmaWcuYWxpZ24gPSAiY2VudGVyIn0KcGxvdHMgPC0gRmVhdHVyZVBsb3Qod29sZnJ1bSwgZmVhdHVyZXM9Yyhhcy52ZWN0b3IobWFya2Vyc191JGdlbmUpWzE6MTBdLCBhcy52ZWN0b3IobWFya2Vyc19sJGdlbmUpWzE6MTBdKSwgcHQuc2l6ZT0xLCBjb21iaW5lPUYpCnBsb3RfZ3JpZChwbG90bGlzdD1wbG90cywgbmNvbD0yKQpgYGAKClRoZSBVIGFuZCBMIGJyYW5jaCBtYXJrZXJzIGFyZSBjbGVhcmx5IGV4cHJlc3NlZCBpbiB0aGUgdHdvIGNsdXN0ZXJzIGluIHRoZSB0b3AgcmlnaHQgb2YgdGhlIFVNQVAgcGxvdC4gCgpDaGVjayBob3cgbWFueSBvZiB0aGUgbWFya2VyIGdlbmVzIGFyZSBmb3VuZCBpbiBlYWNoIGNsdXN0ZXIuIAoKYGBge3J9CmdldF9nZW5lX292ZXJsYXBfcGVyX2NsdXN0ZXIgPC0gZnVuY3Rpb24obWluX2xvZ0ZDLCBuX2dlbmVzKXsKICBwb3NfbWFya2VycyA8LSBtYXJrZXJzW21hcmtlcnMkYXZnX2xvZ0ZDID4gbWluX2xvZ0ZDLF0KCiAgZ2VuZXNfUCA8LSBjKGFzLnZlY3RvcihtYXJrZXJzX1QxVDJUMyRnZW5lKVsxOm5fZ2VuZXNdKQogICNnZW5lc19QIDwtIGMoYXMudmVjdG9yKG1hcmtlcnNfVDFUMlQzJGdlbmUpWzE6bl9nZW5lc10sIGFzLnZlY3RvcihtYXJrZXJzX1Q0VDUkZ2VuZSlbMTpuX2dlbmVzXSkKICBnZW5lc19VIDwtIGFzLnZlY3RvcihtYXJrZXJzX3UkZ2VuZSlbMTpuX2dlbmVzXQogIGdlbmVzX0wgPC0gYXMudmVjdG9yKG1hcmtlcnNfbCRnZW5lKVsxOm5fZ2VuZXNdCiAgYWxsX2dlbmVzIDwtIHVuaXF1ZShjKGdlbmVzX1AsIGdlbmVzX1UsIGdlbmVzX0wpKQogIAogIGRmIDwtIGFzLmRhdGEuZnJhbWUobWF0cml4KG5jb2w9NCwgbnJvdz1sZW5ndGgodW5pcXVlKHBvc19tYXJrZXJzJGNsdXN0ZXIpKSkpCiAgY29sbmFtZXMoZGYpIDwtIGMoJ3RvdGFsX292ZXJsYXAnLCAnb3ZlcmxhcF9QJywgJ292ZXJsYXBfTCcsICdvdmVybGFwX1UnKQogIHJvd25hbWVzKGRmKSA8LSB1bmlxdWUocG9zX21hcmtlcnMkY2x1c3RlcikKCiAgZm9yIChpIGluIDE6bGVuZ3RoKHVuaXF1ZShwb3NfbWFya2VycyRjbHVzdGVyKSkpewogICAgZ2VuZXNfY2x1c3RlciA8LSBhcy52ZWN0b3IocG9zX21hcmtlcnNbcG9zX21hcmtlcnMkY2x1c3RlciA9PSBpLF0kZ2VuZSkKICAgIGRmW2ksICdvdmVybGFwX1AnXSA8LSByb3VuZChsZW5ndGgoaW50ZXJzZWN0KGdlbmVzX2NsdXN0ZXIsIGdlbmVzX1ApKSAvIGxlbmd0aChnZW5lc19QKSwgMikKICAgIGRmW2ksICdvdmVybGFwX0wnXSA8LSByb3VuZChsZW5ndGgoaW50ZXJzZWN0KGdlbmVzX2NsdXN0ZXIsIGdlbmVzX0wpKSAvIGxlbmd0aChnZW5lc19MKSwgMikKICAgIGRmW2ksICdvdmVybGFwX1UnXSA8LSByb3VuZChsZW5ndGgoaW50ZXJzZWN0KGdlbmVzX2NsdXN0ZXIsIGdlbmVzX1UpKSAvIGxlbmd0aChnZW5lc19VKSwgMikKICAgIGRmW2ksICd0b3RhbF9vdmVybGFwJ10gPC0gcm91bmQobGVuZ3RoKGludGVyc2VjdChnZW5lc19jbHVzdGVyLCBhbGxfZ2VuZXMpKSAvIGxlbmd0aChhbGxfZ2VuZXMpLCAyKQogIH0KICByZXR1cm4oZGYpCn0KCnByaW50X3RvcF9jbHVzdGVycyA8LSBmdW5jdGlvbihkZil7CiAgcHJpbnQocGFzdGUoJ1A6ICcsIHRvU3RyaW5nKHJvd25hbWVzKGRmW29yZGVyKC1kZiRvdmVybGFwX1ApLF1bMTozLF0pKSwgc2VwPScnKSkKICBwcmludChwYXN0ZSgnTDogJywgdG9TdHJpbmcocm93bmFtZXMoZGZbb3JkZXIoLWRmJG92ZXJsYXBfTCksXVsxOjMsXSkpLCBzZXA9JycpKQogIHByaW50KHBhc3RlKCdVOiAnLCB0b1N0cmluZyhyb3duYW1lcyhkZltvcmRlcigtZGYkb3ZlcmxhcF9VKSxdWzE6MyxdKSksIHNlcD0nJykpCn0KCmBgYAoKVGFibGUgc2hvd3MgdGhlIHBlcmNlbnRhZ2Ugb2YgZ2VuZXMgd2l0aCBhdmdMb2dGQyA+IDAuNyB0aGF0IHdhcyBmb3VuZCBpbiB0aGUgY2x1c3Rlci4gU29ydCBvbiBjb2x1bW5zIHRvIGdldCB0aGUgdG9wIGNsdXN0ZXJzLgoKYGBge3J9CmxvZ2ZjXzAuNV9nZW5lc18xMDAgPC0gZ2V0X2dlbmVfb3ZlcmxhcF9wZXJfY2x1c3RlcigwLjUsIDEwMCkKZGF0YXRhYmxlKGxvZ2ZjXzAuNV9nZW5lc18xMDApCmBgYAoKQ2hlY2sgdGhlIHRvcCA1IGNsdXN0ZXJzIHBlciBicmFuY2ggZm9yIGRpZmZlcmVudCBuX2dlbmVzIGFuZCBtaW4gbG9nRkMKCmBgYHtyfQpsb2dmYyA8LSBjKDAuMjUsIDAuNSwgMC43KQpuX2dlbmVzIDwtIGMoMTAwLCAxMDAsIDEwMCkKZm9yIChpIGluIDE6bGVuZ3RoKGxvZ2ZjKSl7CiAgcHJpbnQocGFzdGUoJ21pbl9sb2dGQzogJywgbG9nZmNbaV0sICcgfCBuX2dlbmVzOiAnLCBuX2dlbmVzW2ldLCBzZXA9JycpKQogIGRmIDwtIGdldF9nZW5lX292ZXJsYXBfcGVyX2NsdXN0ZXIobG9nZmNbaV0sIG5fZ2VuZXNbaV0pCiAgcHJpbnRfdG9wX2NsdXN0ZXJzKGRmKQp9CmBgYAoKVGhlcmUgaXMgc29tZSBvdmVybGFwIGJldHdlZW4gYnJhbmNoZXMgd2hpY2ggaXMgZ29vZC4gQ2x1c3RlciAxMSBpcyBzaGFyZWQgYmV0d2VlbiBQIGFuZCBMLCBjbHVzdGVyIDE0IGlzIHNoYXJlZCBiZXR3ZWVuIFAgYW5kIFUgYW5kIGNsdXN0ZXIgMjMgaXMgc2hhcmVkIGJldHdlZW4gTCBhbmQgVS4gVGhpcyB3b3VsZCBpbmRpY2F0ZSB0aGF0IGNsdXN0ZXIgMjQgY29udGFpbnMgbW9zdCBpbW1hdHVyZSBwcmVhZGlwb2N5dGVzLCBjbHVzdGVyIDEwIGNvbnRhaW5zIG1vc3QgbWF0dXJlIEwgYnJhbmNoIGNlbGxzIGFuZCBjbHVzdGVyIDIyIGNvbnRhaW5zIG1vc3QgbWF0dXJlIFUgYnJhbmNoIGNlbGxzLlxcCgpCYXNlZCBvbiB0aGUgcmVzdWx0czpcXApQID0gMjRcXApMID0gMTFcXApVID0gMTRcXAoKSHlwb3RoZXNpczogY2x1c3RlciAyMyByZXByZXNlbnRzIHByZWFkaXBvY3l0ZXMgYXQgdGhlIHN0YXJ0IG9mIGRpZmZlcmVudGF0aW9uICh0aGUgY2VsbCBzdGF0ZXMgYmV0d2VlbiBUMyBhbmQgVDQgaW4gMTgwODMxIGRhdGEgdGhhdCB3ZSBtaXNzZWQpLiBDbHVzdGVyIDUgcmVwcmVzZW50cyBldmVuIG1vcmUgbWF0dXJlIG1ldGFib2xpYyBjZWxscyBhbmQgY2x1c3RlciAxMSByZXByZXNlbnRzIG1vcmUgbWF0dXJlIEVDTSBjZWxscy5cXAoKQ2x1c3RlcnMgMjIgc2hhcmVzIG1vc3QgZ2VuZXMgd2l0aCB0aGUgUCBicmFuY2guIENsdXN0ZXIgMjMgbW9zdCB3aXRoIHRoZSBVIGJyYW5jaC4gKHNlZSBkYXRhdGFibGUgYWJvdmUpLiBUaGVzZSBjb3VsZCBhbHNvIHJlcHJlc2VudCB0aGUgcHJlYWRpcG9jeXRlcyBhdCBzdGFydCBvZiBkaWZmZXJlbnRpYXRpb24gb3IgdGhlIGNlbGxzIHRoYXQgdHJhbnNmZXIgYmFjayB0byBwcm9nZW5pdG9yIGNlbGxzLiBcXAoKYGBge3J9ClVNQVBQbG90KHdvbGZydW0sIGdyb3VwLmJ5PSdzZXVyYXRfY2x1c3RlcnMnLCBsYWJlbD1UKQpgYGAKCmBgYHtyfQojSWRlbnRzKHdvbGZydW0pIDwtIHdvbGZydW1AbWV0YS5kYXRhJHNldXJhdF9jbHVzdGVycwojcHJlYWRpcG9jeXRlX3N1YnNldCA8LSBzdWJzZXQod29sZnJ1bSwgaWRlbnRzPWMoNSwgMTQsIDIzLCAxMSwgMTAsIDIxLCAyMiwgMjQpKQojcHJlYWRpcG9jeXRlX3N1YnNldCA8LSBGaW5kVmFyaWFibGVGZWF0dXJlcyhwcmVhZGlwb2N5dGVfc3Vic2V0KQojcHJlYWRpcG9jeXRlX3N1YnNldCA8LSBTY2FsZURhdGEocHJlYWRpcG9jeXRlX3N1YnNldCkKI3ByZWFkaXBvY3l0ZV9zdWJzZXQgPC0gUnVuUENBKG9iamVjdD1wcmVhZGlwb2N5dGVfc3Vic2V0LCBucGNzPTMwKQojRWxib3dQbG90KHByZWFkaXBvY3l0ZV9zdWJzZXQsIG5kaW1zPTMwKQojcHJlYWRpcG9jeXRlX3N1YnNldCA8LSBGaW5kTmVpZ2hib3JzKG9iamVjdCA9IHByZWFkaXBvY3l0ZV9zdWJzZXQsIGRpbXM9MToxMykKI3ByZWFkaXBvY3l0ZV9zdWJzZXQgPC0gRmluZENsdXN0ZXJzKG9iamVjdCA9IHByZWFkaXBvY3l0ZV9zdWJzZXQsIHJlc29sdXRpb249MC44KQojcHJlYWRpcG9jeXRlX3N1YnNldCA8LSBSdW5UU05FKG9iamVjdCA9IHByZWFkaXBvY3l0ZV9zdWJzZXQsIGRpbXM9MToxMykKI3ByZWFkaXBvY3l0ZV9zdWJzZXQgPC0gUnVuVU1BUChvYmplY3QgPSBwcmVhZGlwb2N5dGVfc3Vic2V0LCBkaW1zPTE6MTMpCiNzYXZlUkRTKHByZWFkaXBvY3l0ZV9zdWJzZXQsICcvcHJvamVjdHMvcHl0cmlrL3NjX2FkaXBvc2UvYW5hbHl6ZV8xMHhfZmx1aWRpZ20vMTB4LWFkaXBvY3l0ZS1hbmFseXNpcy9vdXRwdXQvc2V1cmF0X29iamVjdHMvd29sZnJ1bS93b2xmcnVtLnByZWFkaXBvY3l0ZV9zdWJzZXQucmRzJykKcHJlYWRpcG9jeXRlX3N1YnNldCA8LSByZWFkUkRTKCdvdXRwdXQvc2V1cmF0X29iamVjdHMvd29sZnJ1bS93b2xmcnVtLnByZWFkaXBvY3l0ZV9zdWJzZXQucmRzJykKCnBsb3RfZ3JpZCgKICBVTUFQUGxvdChwcmVhZGlwb2N5dGVfc3Vic2V0LCBncm91cC5ieT0nYWxsX2RhdGFfc2V1cmF0X2NsdXN0ZXJzJywgbGFiZWw9VCksCiAgVFNORVBsb3QocHJlYWRpcG9jeXRlX3N1YnNldCwgZ3JvdXAuYnk9J2FsbF9kYXRhX3NldXJhdF9jbHVzdGVycycsIGxhYmVsPVQpCikKYGBgCgojU2V1cmF0IGludGVncmF0aW9uIG9mIFdvbGZydW0gYW5kIDEweC0xODA4MzEgZGF0YQoKYGBge3IsIGZpZy5oZWlnaHQgPSA4LCBmaWcud2lkdGggPSAxMiwgZmlnLmFsaWduID0gImNlbnRlciJ9CiNhbmNob3JzIDwtIEZpbmRJbnRlZ3JhdGlvbkFuY2hvcnMob2JqZWN0Lmxpc3QgPSBsaXN0KHdvbGZydW0sIGRhdGFfMTgwODMxKSwgZGltcyA9IDE6MjApCiNpbnRlZ3JhdGVkIDwtIEludGVncmF0ZURhdGEoYW5jaG9yc2V0ID0gYW5jaG9ycywgZGltcyA9IDE6MjApCiNzYXZlUkRTKGludGVncmF0ZWQsICcvcHJvamVjdHMvcHl0cmlrL3NjX2FkaXBvc2UvYW5hbHl6ZV8xMHhfZmx1aWRpZ20vMTB4LWFkaXBvY3l0ZS1hbmFseXNpcy9vdXRwdXQvc2V1cmF0X29iamVjdHMvd29sZnJ1bS93b2xmcnVtLjE4MDgzMS5pbnRlZ3JhdGVkLnJkcycpCmludGVncmF0ZWQgPC0gcmVhZFJEUygnb3V0cHV0L3NldXJhdF9vYmplY3RzL3dvbGZydW0vd29sZnJ1bS4xODA4MzEuaW50ZWdyYXRlZC5yZHMnKQppbnRlZ3JhdGVkQG1ldGEuZGF0YVsnZGF0YXNldCddIDwtICcxMHgtMTgwODMxJwppbnRlZ3JhdGVkQG1ldGEuZGF0YVt3aGljaChpcy5uYShpbnRlZ3JhdGVkQG1ldGEuZGF0YSRicmFuY2gpKSwgJ2RhdGFzZXQnXSA8LSAnV29sZnJ1bScKCnBsb3RfZ3JpZCgKICBVTUFQUGxvdChpbnRlZ3JhdGVkLCBncm91cC5ieT0nZGF0YXNldCcpLAogIFVNQVBQbG90KGludGVncmF0ZWQsIGdyb3VwLmJ5PSdzZXVyYXRfY2x1c3RlcnMnLCBsYWJlbD1UKSwKICBVTUFQUGxvdChpbnRlZ3JhdGVkLCBncm91cC5ieT0nYnJhbmNoJyksIG5jb2w9MgopCmBgYAoKVGhlc2UgcmVzdWx0cyBhbHNvIGNvbmZpcm0gdGhhdCB0aGUgTCBicmFuY2ggaXMgY2xvc2VzdCB0byBjbHVzdGVyIDExIGFuZCBVIGlzIGNsb3Nlc3QgdG8gdGhlIFUgYnJhbmNoLlxcCgojU2V1cmF0IGludGVncmF0aW9uIG9mIFdvbGZydW0gcHJlYWRpb3BjeXRlIHN1YnNldCBhbmQgMTB4LTE4MDgzMSBkYXRhCgoKYGBge3IsIGZpZy5oZWlnaHQgPSA4LCBmaWcud2lkdGggPSAxMiwgZmlnLmFsaWduID0gImNlbnRlciJ9CmludGVncmF0ZWQuc3Vic2V0IDwtIHJlYWRSRFMoJ291dHB1dC9zZXVyYXRfb2JqZWN0cy93b2xmcnVtL3dvbGZydW0ucHJlYWRpcG9jeXRlX3N1YnNldC4xODA4MzEuaW50ZWdyYXRlZC5yZHMnKQoKaW50ZWdyYXRlZC5zdWJzZXRAbWV0YS5kYXRhWydkYXRhc2V0J10gPC0gJzEweC0xODA4MzEnCmludGVncmF0ZWQuc3Vic2V0QG1ldGEuZGF0YVt3aGljaChpcy5uYShpbnRlZ3JhdGVkLnN1YnNldEBtZXRhLmRhdGEkYnJhbmNoKSksICdkYXRhc2V0J10gPC0gJ1dvbGZydW0nCmludGVncmF0ZWQuc3Vic2V0IDwtIEFkZE1ldGFEYXRhKGludGVncmF0ZWQuc3Vic2V0LCBtZXRhZGF0YT13b2xmcnVtQG1ldGEuZGF0YVsnc2V1cmF0X2NsdXN0ZXJzJ10pCgpwbG90X2dyaWQoCiAgVU1BUFBsb3QoaW50ZWdyYXRlZC5zdWJzZXQsIGdyb3VwLmJ5PSdkYXRhc2V0JyksCiAgVU1BUFBsb3QoaW50ZWdyYXRlZC5zdWJzZXQsIGdyb3VwLmJ5PSdzZXVyYXRfY2x1c3RlcnMnLCBsYWJlbD1UKSwKICBVTUFQUGxvdChpbnRlZ3JhdGVkLnN1YnNldCwgZ3JvdXAuYnk9J2JyYW5jaCcpLAogIFVNQVBQbG90KGludGVncmF0ZWQuc3Vic2V0LCBncm91cC5ieT0ndGltZXBvaW50JyksIG5jb2w9MgopCmBgYAoKI1ByZWRpY3QgY2VsbCB0eXBlcyB3aXRoIFNldXJhdCdzIFRyYW5zZmVyRGF0YQoKYGBge3J9CndvbGZydW0ucHJlZGljdGVkX2xhYmVscyA8LSByZWFkUkRTKCdvdXRwdXQvc2V1cmF0X29iamVjdHMvd29sZnJ1bS93b2xmcnVtLnByZWRpY3RlZF9sYWJlbHNfMTgwODMxLnJkcycpCmBgYAoKVXNlZCBwY2EsIHBjYS5wcm9qZWN0IGFuZCBjY2EgYXMgZGltcmVkIGZvciBGaW5kVHJhbnNmZXJBbmNob3JzIGFuZCBJbnRlZ3JhdGVEYXRhLiBcXAoKU2NvcmVzIGZvciBQIGNlbGxzCgpgYGB7ciwgZmlnLmhlaWdodCA9IDgsIGZpZy53aWR0aCA9IDEyLCBmaWcuYWxpZ24gPSAiY2VudGVyIn0KcGxvdF9ncmlkKAogIEZlYXR1cmVQbG90KHdvbGZydW0ucHJlZGljdGVkX2xhYmVscywgZmVhdHVyZXM9J3ByZWRpY3Rpb25zX3BjYS5wcmVkaWN0aW9uLnNjb3JlLlByb2dlbml0b3InKSwKICBGZWF0dXJlUGxvdCh3b2xmcnVtLnByZWRpY3RlZF9sYWJlbHMsIGZlYXR1cmVzPSdwcmVkaWN0aW9uc19wY2FfcHJvamVjdC5wcmVkaWN0aW9uLnNjb3JlLlByb2dlbml0b3InKSwKICBGZWF0dXJlUGxvdCh3b2xmcnVtLnByZWRpY3RlZF9sYWJlbHMsIGZlYXR1cmVzPSdwcmVkaWN0aW9uc19jY2EuLnByZWRpY3Rpb24uc2NvcmUuUHJvZ2VuaXRvcicpLCBuY29sPTIKKQpgYGAKClNjb3JlcyBmb3IgVSBjZWxscwoKYGBge3IsIGZpZy5oZWlnaHQgPSA4LCBmaWcud2lkdGggPSAxMiwgZmlnLmFsaWduID0gImNlbnRlciJ9CnBsb3RfZ3JpZCgKICBGZWF0dXJlUGxvdCh3b2xmcnVtLnByZWRpY3RlZF9sYWJlbHMsIGZlYXR1cmVzPSdwcmVkaWN0aW9uc19wY2EucHJlZGljdGlvbi5zY29yZS5NZXRhYm9saWMnKSwKICBGZWF0dXJlUGxvdCh3b2xmcnVtLnByZWRpY3RlZF9sYWJlbHMsIGZlYXR1cmVzPSdwcmVkaWN0aW9uc19wY2FfcHJvamVjdC5wcmVkaWN0aW9uLnNjb3JlLk1ldGFib2xpYycpLAogIEZlYXR1cmVQbG90KHdvbGZydW0ucHJlZGljdGVkX2xhYmVscywgZmVhdHVyZXM9J3ByZWRpY3Rpb25zX2NjYS4ucHJlZGljdGlvbi5zY29yZS5NZXRhYm9saWMnKSwgbmNvbD0yCikKYGBgCgpTY29yZXMgZm9yIEwgY2VsbHMKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gOCwgZmlnLndpZHRoID0gMTIsIGZpZy5hbGlnbiA9ICJjZW50ZXIifQpwbG90X2dyaWQoCiAgRmVhdHVyZVBsb3Qod29sZnJ1bS5wcmVkaWN0ZWRfbGFiZWxzLCBmZWF0dXJlcz0ncHJlZGljdGlvbnNfcGNhLnByZWRpY3Rpb24uc2NvcmUuRUNNJyksCiAgRmVhdHVyZVBsb3Qod29sZnJ1bS5wcmVkaWN0ZWRfbGFiZWxzLCBmZWF0dXJlcz0ncHJlZGljdGlvbnNfcGNhX3Byb2plY3QucHJlZGljdGlvbi5zY29yZS5FQ00nKSwKICBGZWF0dXJlUGxvdCh3b2xmcnVtLnByZWRpY3RlZF9sYWJlbHMsIGZlYXR1cmVzPSdwcmVkaWN0aW9uc19jY2EuLnByZWRpY3Rpb24uc2NvcmUuRUNNJyksIG5jb2w9MgopCmBgYAoKRm9yIGFsbCBwcmVkaWN0aW9ucywgY2hhbmdlIHByZWRpY3RlZCBpZCB0byBOQSBpZiBtYXggc2NvcmUgaXMgYmVsb3cgYSBjZXJ0YWluIHRocmVzaG9sZC4gCgpgYGB7cn0KYXNzaWduX2xhYmVscyA8LSBmdW5jdGlvbihjb2xuYW1lLCB0aHJlc2hvbGQ9MC41KXsKICBwcmVkX2lkcyA8LSB1bmxpc3QoYXMudmVjdG9yKGFwcGx5KHdvbGZydW0ucHJlZGljdGVkX2xhYmVsc0BtZXRhLmRhdGFbLGMocGFzdGUoY29sbmFtZSwnLnByZWRpY3Rpb24uc2NvcmUubWF4Jywgc2VwPScnKSwgcGFzdGUoY29sbmFtZSwgJy5wcmVkaWN0ZWQuaWQnLCBzZXA9JycpKV0sIDEsIGZ1bmN0aW9uKHgpewogICAgaWYgKHhbWzFdXSA8IHRocmVzaG9sZCl7CiAgICAgIHJldHVybihOQSkKICAgIH0gZWxzZXsKICAgICAgcmV0dXJuKHhbWzJdXSkKICAgIH0KICB9KSkpCiAgcmV0dXJuKHByZWRfaWRzKQp9Cgpmb3IgKGNvbCBpbiBjKCdwcmVkaWN0aW9uc19wY2FfcHJvamVjdCcsICdwcmVkaWN0aW9uc19wY2EnLCAncHJlZGljdGlvbnNfY2NhLicpKXsKICBmb3IgKHQgaW4gYygwLjUsIDAuNywgMC45LCAwLjk1LCAwLjk5KSl7CiAgICBwcmVkcyA8LSBhc3NpZ25fbGFiZWxzKGNvbCwgdCkKICAgIHdvbGZydW0ucHJlZGljdGVkX2xhYmVscyA8LSBBZGRNZXRhRGF0YSh3b2xmcnVtLnByZWRpY3RlZF9sYWJlbHMsIHByZWRzLCBjb2wubmFtZT1wYXN0ZShjb2wsICdwcmVkaWN0ZWRfbGFiZWwnLCB0LCBzZXA9Jy4nKSkKICB9Cn0KYGBgCgpUaHJlc2hvbGQgZm9yIHByZWRpY3Rpb24gPSAwLjUKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gOCwgZmlnLndpZHRoID0gMTIsIGZpZy5hbGlnbiA9ICJjZW50ZXIifQpwbG90X2dyaWQoCiAgVU1BUFBsb3Qod29sZnJ1bS5wcmVkaWN0ZWRfbGFiZWxzLCBncm91cC5ieT0ncHJlZGljdGlvbnNfcGNhLnByZWRpY3RlZF9sYWJlbC4wLjUnKSwKICBVTUFQUGxvdCh3b2xmcnVtLnByZWRpY3RlZF9sYWJlbHMsIGdyb3VwLmJ5PSdwcmVkaWN0aW9uc19wY2FfcHJvamVjdC5wcmVkaWN0ZWRfbGFiZWwuMC41JyksCiAgVU1BUFBsb3Qod29sZnJ1bS5wcmVkaWN0ZWRfbGFiZWxzLCBncm91cC5ieT0ncHJlZGljdGlvbnNfY2NhLi5wcmVkaWN0ZWRfbGFiZWwuMC41JyksIG5jb2w9MgopCmBgYAoKVGhyZXNob2xkIGZvciBwcmVkaWN0aW9uID0gMC43CgpgYGB7ciwgZmlnLmhlaWdodCA9IDgsIGZpZy53aWR0aCA9IDEyLCBmaWcuYWxpZ24gPSAiY2VudGVyIn0KcGxvdF9ncmlkKAogIFVNQVBQbG90KHdvbGZydW0ucHJlZGljdGVkX2xhYmVscywgZ3JvdXAuYnk9J3ByZWRpY3Rpb25zX3BjYS5wcmVkaWN0ZWRfbGFiZWwuMC43JyksCiAgVU1BUFBsb3Qod29sZnJ1bS5wcmVkaWN0ZWRfbGFiZWxzLCBncm91cC5ieT0ncHJlZGljdGlvbnNfcGNhX3Byb2plY3QucHJlZGljdGVkX2xhYmVsLjAuNycpLAogIFVNQVBQbG90KHdvbGZydW0ucHJlZGljdGVkX2xhYmVscywgZ3JvdXAuYnk9J3ByZWRpY3Rpb25zX2NjYS4ucHJlZGljdGVkX2xhYmVsLjAuNycpLCBuY29sPTIKKQpgYGAKClRocmVzaG9sZCBmb3IgcHJlZGljdGlvbiA9IDAuOQoKYGBge3IsIGZpZy5oZWlnaHQgPSA4LCBmaWcud2lkdGggPSAxMiwgZmlnLmFsaWduID0gImNlbnRlciJ9CnBsb3RfZ3JpZCgKICBVTUFQUGxvdCh3b2xmcnVtLnByZWRpY3RlZF9sYWJlbHMsIGdyb3VwLmJ5PSdwcmVkaWN0aW9uc19wY2EucHJlZGljdGVkX2xhYmVsLjAuOScpLAogIFVNQVBQbG90KHdvbGZydW0ucHJlZGljdGVkX2xhYmVscywgZ3JvdXAuYnk9J3ByZWRpY3Rpb25zX3BjYV9wcm9qZWN0LnByZWRpY3RlZF9sYWJlbC4wLjknKSwKICBVTUFQUGxvdCh3b2xmcnVtLnByZWRpY3RlZF9sYWJlbHMsIGdyb3VwLmJ5PSdwcmVkaWN0aW9uc19jY2EuLnByZWRpY3RlZF9sYWJlbC4wLjknKSwgbmNvbD0yCikKYGBgCgpPbmx5IHNob3cgcHJlYWRpcG9jeXRlcwoKYGBge3J9CmNsdXN0ZXJzIDwtIGMoMjQsIDIyLCAxMSwgMTAsIDIzLCA1LCAxNCkKCmFkaXBvY3l0ZXMgPC0gdW5saXN0KGxhcHBseSh3b2xmcnVtLnByZWRpY3RlZF9sYWJlbHNAbWV0YS5kYXRhJFJOQV9zbm5fcmVzLjAuOCwgZnVuY3Rpb24oeCl7CiAgaWYgKHggJWluJSBjbHVzdGVycyl7CiAgICByZXR1cm4oJ3ByZWFkaXBvY3l0ZScpCiAgfSBlbHNlIHsKICAgIHJldHVybignbm9uLXByZWFkaXBvY3l0ZScpCiAgfQp9KSkKCndvbGZydW0ucHJlZGljdGVkX2xhYmVsc0BtZXRhLmRhdGFbJ3ByZWFkaXBvY3l0ZXMnXSA8LSBhZGlwb2N5dGVzCgpmb3IgKGNvbCBpbiBjKCdwcmVkaWN0aW9uc19wY2FfcHJvamVjdCcsICdwcmVkaWN0aW9uc19wY2EnLCAncHJlZGljdGlvbnNfY2NhLicpKXsKICBmb3IgKHQgaW4gYygwLjUsIDAuNywgMC45LCAwLjk1LCAwLjk5KSl7CiAgICBwcmVkcyA8LSBhc3NpZ25fbGFiZWxzKGNvbCwgdCkKICAgIHdvbGZydW0ucHJlZGljdGVkX2xhYmVscyA8LSBBZGRNZXRhRGF0YSh3b2xmcnVtLnByZWRpY3RlZF9sYWJlbHMsIHByZWRzLCBjb2wubmFtZT1wYXN0ZShjb2wsICdwcmVkaWN0ZWRfbGFiZWwnLCB0LCBzZXA9Jy4nKSkKICB9Cn0KCmBgYAoKCiNGaWd1cmVzCgpgYGB7ciwgZmlnLmhlaWdodCA9IDQsIGZpZy53aWR0aCA9IDYsIGZpZy5hbGlnbiA9ICJjZW50ZXIifQoKbGFiZWxzIDwtIHVubGlzdChsYXBwbHkod29sZnJ1bS5wcmVkaWN0ZWRfbGFiZWxzQG1ldGEuZGF0YSRwcmVkaWN0aW9uc19wY2EucHJlZGljdGVkX2xhYmVsLjAuNywgZnVuY3Rpb24oeCl7CiAgaWYgKGlzLm5hKHgpKXsKICAgIHJldHVybignTm9uLW1hdGNoaW5nIGNlbGxzJykKICB9IGVsc2UgaWYoeCA9PSAnRUNNJyl7CiAgICByZXR1cm4oJ0wnKQogIH0gZWxzZSBpZih4ID09ICdNZXRhYm9saWMnKXsKICAgIHJldHVybignVScpCiAgfSBlbHNlIGlmICh4ID09ICdQcm9nZW5pdG9yJyl7CiAgICByZXR1cm4oJ1AnKQogIH0KfSkpCgp3b2xmcnVtLnByZWRpY3RlZF9sYWJlbHNAbWV0YS5kYXRhWydwcmVkaWN0aW9uc19wY2EucHJlZGljdGVkX2xhYmVsLjAuN19sYWJlbHMnXSA8LSBsYWJlbHMKCndvbGZydW0ucHJlZGljdGVkX2xhYmVsc0BtZXRhLmRhdGFbJ3ByZWRpY3Rpb25zX3BjYS5wcmVkaWN0ZWRfbGFiZWwuMC43X2xhYmVscyddIDwtIGZhY3Rvcih3b2xmcnVtLnByZWRpY3RlZF9sYWJlbHNAbWV0YS5kYXRhJHByZWRpY3Rpb25zX3BjYS5wcmVkaWN0ZWRfbGFiZWwuMC43X2xhYmVscywgbGV2ZWxzID0gYygiUCIsICJMIiwgIlUiLCAnTm9uLW1hdGNoaW5nIGNlbGxzJykpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQgPSA1LCBmaWcud2lkdGggPSA4LCBmaWcuYWxpZ24gPSAiY2VudGVyIn0KY29sb3JtYXAuYnJhbmNoZXMgPC0gYygKICBQPSIjZWNkZDgzIiwKICBVPSIjZTI3MjY4IiwKICBMPSIjOTNjOGJjIiwKICAnTm9uLW1hdGNoaW5nIGNlbGxzJz0nIzdhN2E3YScpCgpwX3ByZWRpY3Rpb25zIDwtIFVNQVBQbG90KHdvbGZydW0ucHJlZGljdGVkX2xhYmVscywgZ3JvdXAuYnk9J3ByZWRpY3Rpb25zX3BjYS5wcmVkaWN0ZWRfbGFiZWwuMC43X2xhYmVscycsIGNvbHM9Y29sb3JtYXAuYnJhbmNoZXMsIG5vLmF4ZXM9VCkgKyB0aGVtZShsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT0xMiksIGxlZ2VuZC5rZXkuaGVpZ2h0PXVuaXQoMC40LCAnY20nKSwgYXhpcy50ZXh0ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCBwbG90Lm1hcmdpbj1ncmlkOjp1bml0KGMoMCwwLDAsMCksICJtbSIpKSArIGxhYnMoY29sb3I9J1NldXJhdCBwcmVkaWN0aW9uJykgCnBfcHJlZGljdGlvbnMKYGBgCgpgYGB7cn0KI3NhdmVfcGxvdCgiZmlndXJlcy9maWd1cmVzX3BhcGVyL21haW5fZmlndXJlcy9GaWd1cmVfd29sZnJ1bS9VTUFQX3dvbGZydW1fcHJlZGljdGVkLWxhYmVsc18xODA4MzEucGRmIiwgcF9wcmVkaWN0aW9ucywgYmFzZV93aWR0aD04LCBiYXNlX2hlaWdodD01KQpgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNSwgZmlnLndpZHRoID0gNi41LCBmaWcuYWxpZ24gPSAiY2VudGVyIn0KcF9jbHVzdGVycyA8LSBVTUFQUGxvdCh3b2xmcnVtLnByZWRpY3RlZF9sYWJlbHMsIGdyb3VwLmJ5PSdSTkFfc25uX3Jlcy4wLjgnLCBsYWJlbD1ULCBuby5heGVzPVQsIG5vLmxlZ2VuZD1UKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwgYXhpcy50ZXh0ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCBwbG90Lm1hcmdpbj1ncmlkOjp1bml0KGMoMCwwLDAsMCksICJtbSIpKQpwX2NsdXN0ZXJzCmBgYAoKYGBge3J9CiNzYXZlX3Bsb3QoImZpZ3VyZXMvZmlndXJlc19wYXBlci9tYWluX2ZpZ3VyZXMvRmlndXJlX3dvbGZydW0vVU1BUF93b2xmcnVtX2NsdXN0ZXJzLnBkZiIsIHBfY2x1c3RlcnMsIGJhc2Vfd2lkdGg9NiwgYmFzZV9oZWlnaHQ9NSkKYGBgCgoKYGBge3J9CiNmZWF0dXJlcGxvdHMKI3dpZGh0PTEzCiN1Y3AyX2ZwIDwtIGZlYXR1cmVwbG90c19sZWckVUNQMiArIHNjYWxlX2NvbG9yX2dyYWRpZW50KG5hbWU9J0V4cHJlc3Npb24nLCBsb3c9J2dyYXknLCAjaGlnaD0nYmx1ZScsIGd1aWRlPSdjb2xvcmJhcicsIGxpbWl0cz1jKDAsNSkpICsgdGhlbWUocGxvdC50aXRsZT1lbGVtZW50X2JsYW5rKCksICNsZWdlbmQudGl0bGU9ZWxlbWVudF90ZXh0KHNpemU9MjApLCBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT0yMCksIGxlZ2VuZC5rZXkuaGVpZ2h0ID0gI3VuaXQoMS4zLCAnY20nKSkKCgojZGNuX2ZwIDwtIGZlYXR1cmVwbG90c19ub2xlZyREQ04gKyB0aGVtZShwbG90LnRpdGxlPWVsZW1lbnRfYmxhbmsoKSkKCmFkaXBvcSA8LSBGZWF0dXJlUGxvdCh3b2xmcnVtLnByZWRpY3RlZF9sYWJlbHMsIGZlYXR1cmVzPSdBRElQT1EnKSArIE5vTGVnZW5kKCkgKyBOb0F4ZXMoKSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0yMCkpICsgc2NhbGVfY29sb3JfZ3JhZGllbnQobmFtZT0nRXhwcmVzc2lvbicsIGxvdz0nZ3JheScsIGhpZ2g9J2JsdWUnLCBndWlkZT0nY29sb3JiYXInLCBsaW1pdHM9YygwLDUpKQoKbGlwZSA8LSBGZWF0dXJlUGxvdCh3b2xmcnVtLnByZWRpY3RlZF9sYWJlbHMsIGZlYXR1cmVzPSdMSVBFJykgKyBOb0xlZ2VuZCgpICsgTm9BeGVzKCkgKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MjApKSArIHNjYWxlX2NvbG9yX2dyYWRpZW50KG5hbWU9J0V4cHJlc3Npb24nLCBsb3c9J2dyYXknLCBoaWdoPSdibHVlJywgZ3VpZGU9J2NvbG9yYmFyJywgbGltaXRzPWMoMCw1KSkKCmFwb2QgPC0gRmVhdHVyZVBsb3Qod29sZnJ1bS5wcmVkaWN0ZWRfbGFiZWxzLCBmZWF0dXJlcz0nQVBPRCcpICsgTm9MZWdlbmQoKSArIE5vQXhlcygpICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTIwKSkgKyBzY2FsZV9jb2xvcl9ncmFkaWVudChuYW1lPSdFeHByZXNzaW9uJywgbG93PSdncmF5JywgaGlnaD0nYmx1ZScsIGd1aWRlPSdjb2xvcmJhcicsIGxpbWl0cz1jKDAsNSkpCgpkY24gPC0gRmVhdHVyZVBsb3Qod29sZnJ1bS5wcmVkaWN0ZWRfbGFiZWxzLCBmZWF0dXJlcz0nRENOJykgKyBOb0F4ZXMoKSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0yMCksIGxlZ2VuZC50ZXh0PWVsZW1lbnRfdGV4dChzaXplPTIwKSwgbGVnZW5kLmtleS5oZWlnaHQgPSB1bml0KDEuMywgJ2NtJykpICsgc2NhbGVfY29sb3JfZ3JhZGllbnQobmFtZT0nRXhwcmVzc2lvbicsIGxvdz0nZ3JheScsIGhpZ2g9J2JsdWUnLCBndWlkZT0nY29sb3JiYXInLCBsaW1pdHM9YygwLDUpKSAKCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQgPSA0LCBmaWcud2lkdGggPSAxNiwgZmlnLmFsaWduID0gImNlbnRlciJ9CmcgPC0gcGxvdF9ncmlkKAogIGFkaXBvcSwgbGlwZSwgYXBvZCwgZGNuLCBuY29sPTQsICByZWxfd2lkdGhzPWMoMSwgMSwgMSwgMS4zKQopCmcKYGBgCgpgYGB7cn0KI3NhdmVfcGxvdCgiLi4vZmlndXJlcy9maWd1cmVzX3BhcGVyL21haW5fZmlndXJlcy9GaWd1cmVfd29sZnJ1bS9mZWF0dXJlcGxvdHMucGRmIiwgZywgYmFzZV93aWR0aD0xNiwgYmFzZV9oZWlnaHQ9NCkKYGBgCgpFQkYyIGFuZCBMRVAKCmBgYHtyfQplYmYyIDwtIEZlYXR1cmVQbG90KHdvbGZydW0ucHJlZGljdGVkX2xhYmVscywgZmVhdHVyZXM9J0VCRjInKSArIE5vQXhlcygpICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTIwKSwgbGVnZW5kLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MjApLCBsZWdlbmQua2V5LmhlaWdodCA9IHVuaXQoMS4zLCAnY20nKSkgKyBzY2FsZV9jb2xvcl9ncmFkaWVudChuYW1lPSdFeHByZXNzaW9uJywgbG93PSdncmF5JywgaGlnaD0nYmx1ZScsIGd1aWRlPSdjb2xvcmJhcicpIAoKcHBhcmcgPC0gRmVhdHVyZVBsb3Qod29sZnJ1bS5wcmVkaWN0ZWRfbGFiZWxzLCBmZWF0dXJlcz0nUFBBUkcnKSArIE5vQXhlcygpICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTIwKSwgbGVnZW5kLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MjApLCBsZWdlbmQua2V5LmhlaWdodCA9IHVuaXQoMS4zLCAnY20nKSkgKyBzY2FsZV9jb2xvcl9ncmFkaWVudChuYW1lPSdFeHByZXNzaW9uJywgbG93PSdncmF5JywgaGlnaD0nYmx1ZScsIGd1aWRlPSdjb2xvcmJhcicpIAoKbGVwIDwtIEZlYXR1cmVQbG90KHdvbGZydW0ucHJlZGljdGVkX2xhYmVscywgZmVhdHVyZXM9J0xFUCcpICsgTm9BeGVzKCkgKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MjApLCBsZWdlbmQudGV4dD1lbGVtZW50X3RleHQoc2l6ZT0yMCksIGxlZ2VuZC5rZXkuaGVpZ2h0ID0gdW5pdCgxLjMsICdjbScpKSArIHNjYWxlX2NvbG9yX2dyYWRpZW50KG5hbWU9J0V4cHJlc3Npb24nLCBsb3c9J2dyYXknLCBoaWdoPSdibHVlJywgZ3VpZGU9J2NvbG9yYmFyJykgCgp1Y3AxIDwtIEZlYXR1cmVQbG90KHdvbGZydW0ucHJlZGljdGVkX2xhYmVscywgZmVhdHVyZXM9J1VDUDEnKSArIE5vQXhlcygpICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTIwKSwgbGVnZW5kLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MjApLCBsZWdlbmQua2V5LmhlaWdodCA9IHVuaXQoMS4zLCAnY20nKSkgKyBzY2FsZV9jb2xvcl9ncmFkaWVudChuYW1lPSdFeHByZXNzaW9uJywgbG93PSdncmF5JywgaGlnaD0nYmx1ZScsIGd1aWRlPSdjb2xvcmJhcicpIAoKZWJmMnZsbiA8LSBWbG5QbG90KHdvbGZydW0ucHJlZGljdGVkX2xhYmVscywgZmVhdHVyZXM9J0VCRjInLCBncm91cC5ieT0nUk5BX3Nubl9yZXMuMC44JywgcHQuc2l6ZT0tMSkgKyBOb0xlZ2VuZCgpCgpsZXB2bG4gPC0gVmxuUGxvdCh3b2xmcnVtLnByZWRpY3RlZF9sYWJlbHMsIGZlYXR1cmVzPSdMRVAnLCBncm91cC5ieT0nUk5BX3Nubl9yZXMuMC44JywgcHQuc2l6ZT0wLjEpICsgTm9MZWdlbmQoKQoKdWNwMXZsbiA8LSBWbG5QbG90KHdvbGZydW0ucHJlZGljdGVkX2xhYmVscywgZmVhdHVyZXM9J1VDUDEnLCBncm91cC5ieT0nUk5BX3Nubl9yZXMuMC44JywgcHQuc2l6ZT0wLjEpICsgTm9MZWdlbmQoKQoKcHBhcmd2bG4gPC0gVmxuUGxvdCh3b2xmcnVtLnByZWRpY3RlZF9sYWJlbHMsIGZlYXR1cmVzPSdQUEFSRycsIGdyb3VwLmJ5PSdSTkFfc25uX3Jlcy4wLjgnLCBwdC5zaXplPTAuMSkgKyBOb0xlZ2VuZCgpCgpgYGAKCmBgYHtyfQojc2F2ZV9wbG90KCIuLi9maWd1cmVzL2ZpZ3VyZXNfcGFwZXIvbWFpbl9maWd1cmVzL0ZpZ3VyZV93b2xmcnVtL2ViZjIucGRmIiwgZWJmMiwgYmFzZV93aWR0aD01LCBiYXNlX2hlaWdodD00KQojc2F2ZV9wbG90KCIuLi9maWd1cmVzL2ZpZ3VyZXNfcGFwZXIvbWFpbl9maWd1cmVzL0ZpZ3VyZV93b2xmcnVtL2ViZjJ2bG4ucGRmIiwgZWJmMnZsbiwgYmFzZV93aWR0aD02LCBiYXNlX2hlaWdodD0yKQoKI3NhdmVfcGxvdCgiLi4vZmlndXJlcy9maWd1cmVzX3BhcGVyL21haW5fZmlndXJlcy9GaWd1cmVfd29sZnJ1bS9wcGFyZy5wZGYiLCBwcGFyZywgYmFzZV93aWR0aD01LCBiYXNlX2hlaWdodD00KQojc2F2ZV9wbG90KCIuLi9maWd1cmVzL2ZpZ3VyZXNfcGFwZXIvbWFpbl9maWd1cmVzL0ZpZ3VyZV93b2xmcnVtL3BwYXJndmxuLnBkZiIsIHBwYXJndmxuLCBiYXNlX3dpZHRoPTYsIGJhc2VfaGVpZ2h0PTIpCgojc2F2ZV9wbG90KCIuLi9maWd1cmVzL2ZpZ3VyZXNfcGFwZXIvbWFpbl9maWd1cmVzL0ZpZ3VyZV93b2xmcnVtL3VjcDEucGRmIiwgdWNwMSwgYmFzZV93aWR0aD01LCBiYXNlX2hlaWdodD00KQojc2F2ZV9wbG90KCIuLi9maWd1cmVzL2ZpZ3VyZXNfcGFwZXIvbWFpbl9maWd1cmVzL0ZpZ3VyZV93b2xmcnVtL3VjcDF2bG4ucGRmIiwgdWNwMXZsbiwgYmFzZV93aWR0aD02LCBiYXNlX2hlaWdodD0yKQoKI3NhdmVfcGxvdCgiLi4vZmlndXJlcy9maWd1cmVzX3BhcGVyL21haW5fZmlndXJlcy9GaWd1cmVfd29sZnJ1bS9sZXAucGRmIiwgbGVwLCBiYXNlX3dpZHRoPTUsIGJhc2VfaGVpZ2h0PTQpCiNzYXZlX3Bsb3QoIi4uL2ZpZ3VyZXMvZmlndXJlc19wYXBlci9tYWluX2ZpZ3VyZXMvRmlndXJlX3dvbGZydW0vbGVwdmxuLnBkZiIsIGxlcHZsbiwgYmFzZV93aWR0aD01LCBiYXNlX2hlaWdodD0yKQoKYGBgCgoKYGBge3J9ClVNQVBQbG90KHdvbGZydW0ucHJlZGljdGVkX2xhYmVscywgbGFiZWw9VCwgZ3JvdXAuYnk9J1JOQV9zbm5fcmVzLjAuOCcpIApgYGAKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNiwgZmlnLndpZHRoID0gMTIsIGZpZy5hbGlnbiA9ICJjZW50ZXIifQpWbG5QbG90KHdvbGZydW0ucHJlZGljdGVkX2xhYmVscywgZmVhdHVyZXM9YygnRUJGMicsICdQUEFSRycpLCBncm91cC5ieT0nUk5BX3Nubl9yZXMuMC44JywgcHQuc2l6ZT0tMSwgbmNvbD0xKQpgYGAKCgpgYGB7ciwgZmlnLmhlaWdodCA9IDYsIGZpZy53aWR0aCA9IDYsIGZpZy5hbGlnbiA9ICJjZW50ZXIifQojRUJGMiBhbmQgUFBBUkcKI1BQQVJHOiA1LCAxNCwgMjMKI0VCRjI6IDEwLCAxMSwgMjEsIDIzCgpuZXdfbGFiZWxzIDwtIHVubGlzdChsYXBwbHkod29sZnJ1bS5wcmVkaWN0ZWRfbGFiZWxzQG1ldGEuZGF0YSRSTkFfc25uX3Jlcy4wLjgsIGZ1bmN0aW9uKHgpewogIGlmICh4ICVpbiUgYyg1LCAxNCwgMjMsIDEwLCAxMSwgMjEsIDIzKSl7CiAgICByZXR1cm4oeCkKICB9IGVsc2UgewogICAgcmV0dXJuKE5BKQogIH0KfSkpCgp3b2xmcnVtLnByZWRpY3RlZF9sYWJlbHNAbWV0YS5kYXRhWydsYWJlbHNfY2x1c3RlcnNfcHJlYWRpcG9jeXRlcyddIDwtIG5ld19sYWJlbHMKcCA8LSBVTUFQUGxvdCh3b2xmcnVtLnByZWRpY3RlZF9sYWJlbHMsIGdyb3VwLmJ5PSdsYWJlbHNfY2x1c3RlcnNfcHJlYWRpcG9jeXRlcycsIGxhYmVsPVQpICsgdGhlbWUoYXhpcy50ZXh0ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpY2tzID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLCBwbG90Lm1hcmdpbj1ncmlkOjp1bml0KGMoMCwwLDAsMCksICJtbSIpKSArIE5vTGVnZW5kKCkKcApgYGAKCmBgYHtyfQojc2F2ZV9wbG90KCIuLi9maWd1cmVzL2ZpZ3VyZXNfcGFwZXIvbWFpbl9maWd1cmVzL0ZpZ3VyZV93b2xmcnVtL1VNQVBfYWRpcG9jeXRlX2NsdXN0ZXJzMi5wZGYiLCBwLCBiYXNlX3dpZHRoPTYsIGJhc2VfaGVpZ2h0PTUpCmBgYAoKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gNCwgZmlnLndpZHRoID0gOC41LCBmaWcuYWxpZ24gPSAiY2VudGVyIn0KZWJmMiA8LSBGZWF0dXJlUGxvdCh3b2xmcnVtLnByZWRpY3RlZF9sYWJlbHMsIGZlYXR1cmVzPSdFQkYyJywgcHQuc2l6ZT0wLjUpICsgTm9MZWdlbmQoKSArIE5vQXhlcygpICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTIwKSkgKyBzY2FsZV9jb2xvcl9ncmFkaWVudChuYW1lPSdFeHByZXNzaW9uJywgbG93PSdncmF5JywgaGlnaD0nYmx1ZScsIGd1aWRlPSdjb2xvcmJhcicsIGxpbWl0cz1jKDAsNSkpCgpwcGFyZyA8LSBGZWF0dXJlUGxvdCh3b2xmcnVtLnByZWRpY3RlZF9sYWJlbHMsIGZlYXR1cmVzPSdQUEFSRycsIHB0LnNpemU9MC41KSArIE5vQXhlcygpICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTIwKSwgbGVnZW5kLnRleHQ9ZWxlbWVudF90ZXh0KHNpemU9MTUpLCBsZWdlbmQua2V5LmhlaWdodCA9IHVuaXQoMS4zLCAnY20nKSkgKyBzY2FsZV9jb2xvcl9ncmFkaWVudChuYW1lPSdFeHByZXNzaW9uJywgbG93PSdncmF5JywgaGlnaD0nYmx1ZScsIGd1aWRlPSdjb2xvcmJhcicsIGxpbWl0cz1jKDAsNSkpIAoKZyA8LSBwbG90X2dyaWQoCiAgZWJmMiwgcHBhcmcsIG5jb2w9MiwgcmVsX3dpZHRocyA9IGMoMSwgMS4zKQopCgpnCmBgYAoKYGBge3J9CiNzYXZlX3Bsb3QoIi4uL2ZpZ3VyZXMvZmlndXJlc19wYXBlci9tYWluX2ZpZ3VyZXMvRmlndXJlX3dvbGZydW0vRUJGMl9QUEFSR19wdHNpemUwLjUucGRmIiwgZywgYmFzZV93aWR0aD04LjUsIGJhc2VfaGVpZ2h0PTQpCmBgYAoKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gMTAsIGZpZy53aWR0aCA9IDgsIGZpZy5hbGlnbiA9ICJjZW50ZXIifQpwbG90cyA8LSBWbG5QbG90KHdvbGZydW0ucHJlZGljdGVkX2xhYmVscywgZmVhdHVyZXM9YygnQURJUE9RJywgJ0xJUEUnLCAnUExJTjQnLCAnRkFCUDQnLCAnQURJUkYnLCAnQVBPRCcsICdNR1AnLCAnRENOJywgJ0NDREM4MCcsICdQTEFDOScpLCBncm91cC5ieT0nUk5BX3Nubl9yZXMuMC44JywgcHQuc2l6ZT0tMSwgY29tYmluZT1GKQoKZm9yIChpIGluIDE6bGVuZ3RoKHBsb3RzKSl7CiAgaWYgKGkgPT0gbGVuZ3RoKHBsb3RzKSl7CiAgICBwbG90c1tbaV1dIDwtIHBsb3RzW1tpXV0gKyBOb0xlZ2VuZCgpICsgCiAgICAgIHRoZW1lKHBsb3QudGl0bGU9ZWxlbWVudF9ibGFuaygpLCAKICAgICAgICAgICAgYXhpcy50aXRsZS55PWVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgICAgIGF4aXMubGluZS54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICAgICAgYXhpcy50ZXh0Lng9ZWxlbWVudF90ZXh0KGFuZ2xlPTAsIHNpemU9MTIpLAogICAgICAgICAgICBwbG90Lm1hcmdpbiA9IHVuaXQoYygwLCAwLCAwLCAwKSwgImNtIikpICsgCiAgICAgIGxhYnMoeD0nQ2x1c3RlcicpCiAgfSBlbHNlIHsKICAgIHBsb3RzW1tpXV0gPC0gcGxvdHNbW2ldXSArIE5vTGVnZW5kKCkgKyAKICAgICAgdGhlbWUocGxvdC50aXRsZT1lbGVtZW50X2JsYW5rKCksIAogICAgICAgICAgICBheGlzLnRpdGxlLnk9ZWxlbWVudF9ibGFuaygpLCAKICAgICAgICAgICAgYXhpcy5saW5lLng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICBheGlzLnRpY2tzLng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgICAgICBheGlzLnRleHQueD1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgIGF4aXMudGl0bGUueD1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgICAgIHBsb3QubWFyZ2luID0gdW5pdChjKDAsIDAsIDAsIDApLCAiY20iKSkKICB9Cn0KCnZsbnBsdHMgPC0gcGxvdF9ncmlkKHBsb3RsaXN0PXBsb3RzLCBuY29sPTEsIHJlbF9oZWlnaHRzPWMoMSwxLDEsMSwxLDEsMSwxLDEsMS42KSkKdmxucGx0cwpgYGAKCgpgYGB7cn0KI3NhdmVfcGxvdCgiZmlndXJlcy9maWd1cmVzX3BhcGVyL21haW5fZmlndXJlcy9GaWd1cmVfd29sZnJ1bS92aW9saW5wbG90cy5wZGYiLCBwLCBiYXNlX3dpZHRoPTYsIGJhc2VfaGVpZ2h0PTgpCmBgYAoKU3VwcGxlbWVudGFyeSBmaWd1cmUKCmBgYHtyLCBmaWcuaGVpZ2h0ID0gOCwgZmlnLndpZHRoID0gMTIsIGZpZy5hbGlnbiA9ICJjZW50ZXIifQppbnRlZ3JhdGVkIDwtIHJlYWRSRFMoJ291dHB1dC9zZXVyYXRfb2JqZWN0cy93b2xmcnVtL3dvbGZydW0uMTgwODMxLmludGVncmF0ZWQucmRzJykKc2ZpZyA8LSBwbG90X2dyaWQoCiAgVU1BUFBsb3QoaW50ZWdyYXRlZCwgZ3JvdXAuYnk9J2RhdGFzZXQnKSwKICBVTUFQUGxvdChpbnRlZ3JhdGVkLCBncm91cC5ieT0nU3RhdGUubGFiZWxzJywgY29scz1jb2xvcm1hcC5icmFuY2hlcyksCiAgVU1BUFBsb3QoaW50ZWdyYXRlZCwgZ3JvdXAuYnk9J1JOQV9zbm5fcmVzLjAuOCcsIGxhYmVsPVQpICsgTm9MZWdlbmQoKSwgbmNvbD0yCikKc2ZpZwpgYGAKCmBgYHtyfQojc2F2ZV9wbG90KCJmaWd1cmVzL2ZpZ3VyZXNfcGFwZXIvc3VwcGxlbWVudGFyeV9maWd1cmVzL3dvbGZydW0vaW50ZWdyYXRpb24ud29sZnJ1bS4xODA4MzEucGRmIiwgc2ZpZywgYmFzZV93aWR0aD0xMiwgYmFzZV9oZWlnaHQ9OCkKYGBgCgo=